/*
 * Copyright (c) 2024 Huawei Device Co., Ltd.
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *     http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */

import { ts, native, HomeCheckHint, Location } from "qvog-dsl";

const SEVERITY = 2;
const DOC_PATH = '';
const DESCRIPTION = 'Detect and report commented-out code in ArkTS or TypeScript files, which should be deleted.';

interface CommentNodeInfo {
    startCol: number;
    pos: number;
    end: number;
    line: number;
};

interface CommentMatch {
    fullMatch: string;
    innerMatch: string | null;
    node: CommentNodeInfo;
};

export default native<HomeCheckHint>()()
    .match((node): node is ts.EndOfFileToken => {
        return node.kind === ts.SyntaxKind.EndOfFileToken;
    })
    .report((node, { api }) => {
        const comments = getAllComments(node);
        for (const comment of comments) {
            if (comment.innerMatch && isValidTsCode(comment.innerMatch)) {
                api.report({
                    location: getLocation(node, comment),
                    severity: SEVERITY,
                    description: DESCRIPTION,
                    docPath: DOC_PATH,
                })
            }
        }
    });

function getAllComments(aNode: ts.Node): CommentMatch[] {
    const comments: CommentMatch[] = [];
    const commentRegex = /\/\/(.*)|\/\*([\s\S]*?)\*\//g;
    const code = aNode.getSourceFile().getFullText();

    let match;
    while ((match = commentRegex.exec(code)) !== null) {
        const fullMatch = match[0];
        let innerMatch: string | null = null;
        if (match[1]) {
            innerMatch = match[1].trim();
        } else if (match[2]) {
            innerMatch = match[2].trim();
        };
        const pos = match.index;
        // 把注释起始位置之前的代码按换行符分割成一个行数组
        const linesBefore = code.slice(0, pos).split('\n');
        // 计算行列号
        const line = linesBefore.length;
        const startCol = linesBefore[linesBefore.length - 1].length + 1;
        const end = pos + fullMatch.length;

        const node: CommentNodeInfo = { startCol, pos, end, line };
        comments.push({ fullMatch, innerMatch, node });

    };
    return comments;
}

function isValidTsCode(code: string): boolean {
    if (!code || code.trim().length === 0) {
        return false;
    }

    // 排除常见文本注释
    const noisePatterns = [
        /^TODO:?/i,
        /^FIXME:?/i,
        /^NOTE:?/i,
        /^HACK:?/i,
        /^XXX:?/i,
        /^\s*[\d\.\-\*●◦]\s/,
        /^[a-zA-Z\s]+$/, // 纯字母和空格
    ];
    if (noisePatterns.some(re => re.test(code))) {
        return false;
    }

    const codeIndicators = [
        /\b(function|const|let|var|class|interface|type|enum|import|export|return|if|else|for|while|switch|case|break|continue|new|this|super|console|window)\b/,
        /^[a-zA-Z_$][a-zA-Z0-9_$]*\s*[:=><({[]/,
        /=>/,
        /\+\+|--/,
        /[{}[\]();]/,
        /==|===|!=|!==|<=|>=|&&|\|\|/,
        /:\s*\w+/,
        /=\s*[^'"]/
    ];

    let score = 0;
    for (const regex of codeIndicators) {
        if (regex.test(code)) {
            score++;
        }
    }

    return score >= 2;
}

function getLocation(node: ts.Node, comment: CommentMatch): Location {
    return {
        file: node.getSourceFile().fileName,
        range: {
            start: {
                line: comment.node.line,
                column: comment.node.startCol,
            },
            end: {
                line: comment.node.line,
                column: comment.node.startCol,
            },
        },
    };
}
